/*
 * @Description:
 * @Version:
 * @Author: Troubadour
 * @Date: 2022-09-14 20:01:54
 * @LastEditors: Troubadour
 * @LastEditTime: 2022-09-15 21:45:27
 */

#include "MyOled.hpp"


MyOled::MyOled(uint8_t addr)
{
    OledAddr = addr;
}


MyOled::MyOled()
{
    OledAddr = 0x3C;
}


MyOled::~MyOled()
{
}


/**
 * @function: OLED_WR_Byte
 * @brief 写入一个字节
 * @param {uint8_t} dat：1字节数据
 * @param {uint8_t} mode：0：表示命令；1：表示数据;
 * @return {*}
 */
void MyOled::OLED_WR_Byte(uint8_t dat, uint8_t mode)
{
    Wire.beginTransmission(0x3c);
    if (mode)
    {
        Wire.write(0x40);
    }
    else
    {
        Wire.write(0x00);
    }
    Wire.write(dat);        // sends one byte
    Wire.endTransmission(); // stop transmitting
}


/**
 * @function: ColorTurn
 * @brief 反显函数
 * @param {uint8_t} mode：1反显，0正常
 * @return {*}
 */
void MyOled::ColorTurn(uint8_t mode)
{
    if (mode == 0)
        OLED_WR_Byte(0xA6, OLED_CMD); //正常显示
    else
        OLED_WR_Byte(0xA7, OLED_CMD); //反色显示
}


/**
 * @function: DisplayTurn
 * @brief 屏幕旋转180度
 * @param {uint8_t} mode：1旋转，0正常
 * @return {*}
 */
void MyOled::DisplayTurn(uint8_t mode)
{
    if (mode == 0)
    {
        OLED_WR_Byte(0xC8, OLED_CMD); //正常显示
        OLED_WR_Byte(0xA1, OLED_CMD);
    }
    else
    {
        OLED_WR_Byte(0xC0, OLED_CMD); //反转显示
        OLED_WR_Byte(0xA0, OLED_CMD);
    }
}


/**
 * @function: Set_Pos
 * @brief 坐标设置
 * @param {uint8_t} x：横向坐标
 * @param {uint8_t} y：纵向坐标
 * @return {*}
 */
void MyOled::Set_Pos(uint8_t x, uint8_t y)
{
    OLED_WR_Byte(0xb0 + y, OLED_CMD);
    OLED_WR_Byte(((x & 0xf0) >> 4) | 0x10, OLED_CMD);
    OLED_WR_Byte((x & 0x0f), OLED_CMD);
}


/**
 * @function: Display_On
 * @brief 开启OLED显示
 * @param {*}
 * @return {*}
 */
void MyOled::Display_On(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
    OLED_WR_Byte(0X14, OLED_CMD); // DCDC ON
    OLED_WR_Byte(0XAF, OLED_CMD); // DISPLAY ON
}


/**
 * @function: Display_Off
 * @brief 关闭OLED显示
 * @param {*}
 * @return {*}
 */
void MyOled::Display_Off(void)
{
    OLED_WR_Byte(0X8D, OLED_CMD); // SET DCDC命令
    OLED_WR_Byte(0X10, OLED_CMD); // DCDC OFF
    OLED_WR_Byte(0XAE, OLED_CMD); // DISPLAY OFF
}


/**
 * @function: Clear
 * @brief 清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
 * @param {*}
 * @return {*}
 */
void MyOled::Clear(void)
{
    uint8_t i, n;
    for (i = 0; i < 8; i++)
    {
        OLED_WR_Byte(0xb0 + i, OLED_CMD); //设置页地址（0~7）
        OLED_WR_Byte(0x00, OLED_CMD);     //设置显示位置—列低地址
        OLED_WR_Byte(0x10, OLED_CMD);     //设置显示位置—列高地址
        for (n = 0; n < 128; n++)
            OLED_WR_Byte(0, OLED_DATA);
    } //更新显示
}


/**
 * @function: Full
 * @brief 填充一个区域
 * @param {uint8_t} x：横向坐标0~127
 * @param {uint8_t} y：纵向坐标0~63
 * @param {uint8_t} sizex：填充宽度
 * @param {uint8_t} sizey：填充高度
 * @param {uint8_t} mode：1点亮；0熄灭
 * @return {*}
 */
void MyOled::Full(uint8_t x, uint8_t y, uint8_t sizex, uint8_t sizey, uint8_t mode)
{
    uint8_t i, m;
    sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
    for (i = 0; i < sizey; i++)
    {
        Set_Pos(x, i + y);
        for (m = 0; m < sizex; m++)
        {
            if(mode)
            {
                OLED_WR_Byte(0xFF, OLED_DATA);
            }
            else
            {
                OLED_WR_Byte(0x00, OLED_DATA);
            }
        }
    }
}


/**
 * @function: ShowChar
 * @brief 在指定位置显示一个字符
 * @param {uint8_t} x：横向坐标0~127
 * @param {uint8_t} y：纵向坐标0~63
 * @param {const uint8_t} chr：字符串
 * @param {uint8_t} sizey：字体大小；6*8、8*16
 * @return {*}
 */
void MyOled::ShowChar(uint8_t x, uint8_t y, const uint8_t chr, uint8_t sizey)
{
    uint8_t c = 0, sizex = sizey / 2, temp;
    uint16_t i = 0, size1;
    if (sizey == 8)
        size1 = 6;
    else
        size1 = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * (sizey / 2);
    c = chr - ' '; //得到偏移后的值
    Set_Pos(x, y);
    for (i = 0; i < size1; i++)
    {
        if (i % sizex == 0 && sizey != 8)
            Set_Pos(x, y++);
        if (sizey == 8)
        {
            temp = pgm_read_byte(&asc2_0806[c][i]);
            OLED_WR_Byte(temp, OLED_DATA); // 6X8字号
        }
        else if (sizey == 16)
        {
            temp = pgm_read_byte(&asc2_1608[c][i]);
            OLED_WR_Byte(temp, OLED_DATA); // 8x16字号
        }
        else
            return;
    }
}


/**
 * @function: Pow
 * @brief: m^n函数
 * @param {uint8_t} m
 * @param {uint8_t} n
 * @return {*}
 */
uint32_t MyOled::Pow(uint8_t m, uint8_t n)
{
    uint32_t result = 1;
    while (n--)
        result *= m;
    return result;
}


/**
 * @function: ShowNum
 * @brief 显示数字
 * @param {uint8_t} x：横向坐标0~127
 * @param {uint8_t} y：纵向坐标0~63
 * @param {uint32_t} num：数字
 * @param {uint8_t} len：显示数字的位数
 * @param {uint8_t} sizey：字体大小；6*8、8*16
 * @return {*}
 */
void MyOled::ShowNum(uint8_t x, uint8_t y, uint32_t num, uint8_t len, uint8_t sizey)
{
    uint8_t t, temp, m = 0;
    uint8_t enshow = 0;
    if (sizey == 8)
        m = 2;
    for (t = 0; t < len; t++)
    {
        temp = (num / Pow(10, len - t - 1)) % 10;
        if (enshow == 0 && t < (len - 1))
        {
            if (temp == 0)
            {
                ShowChar(x + (sizey / 2 + m) * t, y, ' ', sizey);
                continue;
            }
            else
                enshow = 1;
        }
        ShowChar(x + (sizey / 2 + m) * t, y, temp + '0', sizey);
    }
}


/**
 * @function: ShowString
 * @brief 显示字符串
 * @param {uint8_t} x：横向坐标0~127
 * @param {uint8_t} y：纵向坐标0~63
 * @param {const char} *chr：要显示的字符串
 * @param {uint8_t} sizey：字体大小；6*8、8*16
 * @return {*}
 */
void MyOled::ShowString(uint8_t x, uint8_t y, const char *chr, uint8_t sizey)
{
    uint8_t j = 0;
    while (chr[j] != '\0')
    {
        ShowChar(x, y, chr[j++], sizey);
        if (sizey == 8)
            x += 6;
        else
            x += sizey / 2;
    }
}


/**
 * @function: ShowChinese
 * @brief 显示汉字
 * @param {uint8_t} x：横向坐标0~127
 * @param {uint8_t} y：纵向坐标0~63
 * @param {const uint8_t} no：字选择
 * @param {uint8_t} sizey：字体大小；根据自己取模决定
 * @return {*}
 */
void MyOled::ShowChinese(uint8_t x, uint8_t y, const uint8_t no, uint8_t sizey)
{
    uint16_t i, size1 = (sizey / 8 + ((sizey % 8) ? 1 : 0)) * sizey;
    uint8_t temp;
    for (i = 0; i < size1; i++)
    {
        if (i % sizey == 0)
            Set_Pos(x, y++);
        if (sizey == 16)
        {
            temp = pgm_read_byte(&Hzk[no][i]);
            OLED_WR_Byte(temp, OLED_DATA); // 16x16字号
        }
        //    else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);     // 用户添加字号
        else
            return;
    }
}


/**
 * @function: DrawBMP
 * @brief 显示图片
 * @param {uint8_t} x：横向坐标0~127
 * @param {uint8_t} y：纵向坐标0~63
 * @param {uint8_t} sizex：图片宽度
 * @param {uint8_t} sizey：图片高度
 * @param {const uint8_t} BMP：图片的数组
 * @return {*}
 */
void MyOled::DrawBMP(uint8_t x, uint8_t y, uint8_t sizex, uint8_t sizey, const uint8_t BMP[])
{
    uint16_t j = 0;
    uint8_t i, m, temp;
    sizey = sizey / 8 + ((sizey % 8) ? 1 : 0);
    for (i = 0; i < sizey; i++)
    {
        Set_Pos(x, i + y);
        for (m = 0; m < sizex; m++)
        {
            temp = pgm_read_byte(&BMP[j++]);
            OLED_WR_Byte(temp, OLED_DATA);
        }
    }
}


/**
 * @function:Init
 * @brief 初始化OLED
 * @param {*}
 * @return {*}
 */
void MyOled::Init(void)
{
    Wire.begin(OledAddr);
    delay(200);

    OLED_WR_Byte(0xAE, OLED_CMD); //--turn off oled panel
    OLED_WR_Byte(0x00, OLED_CMD); //---set low column address
    OLED_WR_Byte(0x10, OLED_CMD); //---set high column address
    OLED_WR_Byte(0x40, OLED_CMD); //--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
    OLED_WR_Byte(0x81, OLED_CMD); //--set contrast control register
    OLED_WR_Byte(0xCF, OLED_CMD); // Set SEG Output Current Brightness
    OLED_WR_Byte(0xA1, OLED_CMD); //--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
    OLED_WR_Byte(0xC8, OLED_CMD); // Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
    OLED_WR_Byte(0xA6, OLED_CMD); //--set normal display
    OLED_WR_Byte(0xA8, OLED_CMD); //--set multiplex ratio(1 to 64)
    OLED_WR_Byte(0x3f, OLED_CMD); //--1/64 duty
    OLED_WR_Byte(0xD3, OLED_CMD); //-set display offset Shift Mapping RAM Counter (0x00~0x3F)
    OLED_WR_Byte(0x00, OLED_CMD); //-not offset
    OLED_WR_Byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
    OLED_WR_Byte(0x80, OLED_CMD); //--set divide ratio, Set Clock as 100 Frames/Sec
    OLED_WR_Byte(0xD9, OLED_CMD); //--set pre-charge period
    OLED_WR_Byte(0xF1, OLED_CMD); // Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
    OLED_WR_Byte(0xDA, OLED_CMD); //--set com pins hardware configuration
    OLED_WR_Byte(0x12, OLED_CMD);
    OLED_WR_Byte(0xDB, OLED_CMD); //--set vcomh
    OLED_WR_Byte(0x40, OLED_CMD); // Set VCOM Deselect Level
    OLED_WR_Byte(0x20, OLED_CMD); //-Set Page Addressing Mode (0x00/0x01/0x02)
    OLED_WR_Byte(0x02, OLED_CMD); //
    OLED_WR_Byte(0x8D, OLED_CMD); //--set Charge Pump enable/disable
    OLED_WR_Byte(0x14, OLED_CMD); //--set(0x10) disable
    OLED_WR_Byte(0xA4, OLED_CMD); // Disable Entire Display On (0xa4/0xa5)
    OLED_WR_Byte(0xA6, OLED_CMD); // Disable Inverse Display On (0xa6/a7)
    Clear();
    OLED_WR_Byte(0xAF, OLED_CMD); /*display ON*/
}
